#include "Cell.h"


Cell::Cell()
{
	pos.x = 1;
	pos.y = 1;
	direction.borders = new int*[DOWN];	//DOWN here just not to create new constant
	for (int i = 0; i < 4; i++)
	{

		direction.borders[i] = new int;
		*direction.borders[i] = NDEF;
	}
	direction.num_blocked = 0;
	direction.num_free = 0;
	condition = NOT;
	color = GREY;
	//cout<<"Constructor empty working"<<endl;
	//cout<<*this<<endl;
}

Cell::Cell(int xxx, int yyy)
{
	setPos(xxx, yyy);
	cout<<"Constructor xxx yyy working"<<endl;
}

Cell::~Cell(void)
{
}


pair<int, int> Cell::getPos() const
{
	return make_pair(pos.x, pos.y);
}

void Cell::setPos(int xx, int yy)
{
	pos.x = xx;
	pos.y = yy;
}

ostream& operator <<(ostream &stream, Cell p)				//where should it be implemented?
{
	//cout<<"condition: "<<p.condition<<endl;
	//return cout<<p.pos.x<<" "<<p.pos.y<<endl;
	//cout<<"\nOperator <<Cell working"<<endl;
	return stream<<(void *)&p;
}
ostream& operator <<(ostream &stream, Cell *p)
{
	//cout<<"condition: "<<p->condition<<endl;
	//cout<<"\nOperator << *Cell working"<<endl;
	//return cout<<p->pos.x<<" "<<p->pos.y;
	return stream<<(void *)p<<endl;
}

const int Cell::getCondition() const
{
	//cout<<"Condition in getCondition: "<<condition<<endl;
	return condition;
}

int Cell::setCondition(const int num_bl_value)
{
	if (UP == num_bl_value || RIGHT == num_bl_value || DOWN == num_bl_value || LEFT == num_bl_value)
	{
		condition = HALF;
		return 0;
	} 
	else if (num_bl_value != 0)
	{
		condition = READY;
		return 0;
	}
	return 1;
}

void Cell::copyDirection(Direction dir_copy_to, int * const dir_copy_from)
{
	direction.borders[logar(dir_copy_to)] = dir_copy_from;
	//cout<<"copyDirection is working"<<endl;
}

int Cell::setDirectionTo(pair<int, int> dir_to_set, const int state)		//increments condition as well by invoking setCondition
{
	const int num_itertn = 2;
		
	int arr_dirtoset[num_itertn] = {dir_to_set.first, dir_to_set.second};
	int border_state[num_itertn] = {*direction.borders[logar(dir_to_set.first)]};
		
	int num_iter = 1;
	if (dir_to_set.second != 0) 
	{
		num_iter = 2;
		border_state[1] = *direction.borders[logar(dir_to_set.second)];
	}
		
	
	for (int i = 0; i<num_iter; i++)
	{
			if (BLOCKED == state && border_state[i] != FREE) 
			{
				//cout<<"setDirTo BLOCKED working"<<endl;
				*direction.borders[logar(arr_dirtoset[i])] = state;
				if (direction.num_blocked != dir_to_set.first)		//we make sure we do not increment num_blocked if we try to set the same blocked border
				{
					direction.num_blocked += dir_to_set.first;
				}
				if (2 == num_iter && direction.num_blocked != dir_to_set.second)
				{
					direction.num_blocked += dir_to_set.second;
				}
				
				if (1 == setCondition(direction.num_blocked)) return 1;
			}
			else if (FREE == state && border_state[i] != BLOCKED) 
			{
				//cout<<"setDirTo FREE working"<<endl;
				*direction.borders[logar(arr_dirtoset[i])] = state;
				if (direction.num_free != dir_to_set.first)		//we make sure we do not increment num_blocked if we try to set the same blocked border
				{
					direction.num_free += dir_to_set.first;
				}
				if (2 == num_iter && direction.num_free != dir_to_set.second)
				{
					direction.num_free += dir_to_set.second;
				}
				
				if (1 == setCondition(direction.num_free)) return 1;
			}
			else
			{
				cout<<"WE JUST TRIED TO CHANGE STATE TO OPPOSITE. THATS AN ERROOR!!"<<endl;
				return 1;
			}
		
	}
	//cout<<"Direction "<<logar(dir_to_set.first)<<" of "<<this<<" is set to: \n"<<*direction.borders[logar(dir_to_set.first)]<<endl;
	//cout<<"setDirectionBlocked is working"<<endl;
	return 0;
}

pair<int, int> Cell::checkDirectionSwitch(const Color clr)		//returns opposite Direction
{
	//switch is meant to be used by black and white cells. white return what to black. black return where to move.
	if (condition != NOT)
	{
		//cout<<"Condition in CheckDirectionSwitch: "<<condition<<endl;
		//cout<<"direction.num_blocked: "<<direction.num_blocked<<endl;
		//cout<<"direction.num_free: "<<direction.num_free<<endl;
		int value_free_or_blocked = 0;
		if (0 != direction.num_blocked) value_free_or_blocked = direction.num_blocked;
		else value_free_or_blocked = direction.num_free;
		
		switch (value_free_or_blocked)
		{
		case UP:
			return make_pair(DOWN, 0);
		case DOWN:
			return make_pair(UP, 0);
		case LEFT:
			return make_pair(RIGHT, 0);
		case RIGHT:
			return make_pair(LEFT, 0);
		case UP+RIGHT://376
			return make_pair(DOWN, LEFT);//12
		case DOWN+LEFT://12
			return make_pair(UP, RIGHT);//3
		case RIGHT+DOWN://6
			return make_pair(UP, LEFT);//9
		case UP+LEFT://9
			return make_pair(RIGHT, DOWN);//6
		case UP+DOWN://5
			return make_pair(LEFT, RIGHT);//10
		case LEFT+RIGHT://10
			return make_pair(UP, DOWN);//5
		default://SHOULD BE ERRROR!!!!!!!!!!!
			return make_pair(1, 1);
		}
	}
	return make_pair(0, 0);
}
/*
pair<int, int> decomposite(int val_to_dec)
{
	switch (val_to_dec)
	{
	case UP+DOWN:
		return make_pair(UP, DOWN);
	case LEFT+RIGHT:
		return make_pair(LEFT, RIGHT);
	default:
		return make_pair(1, 1);
	}
	return make_pair(0, 0);
}
*/
const Cell::orientation Cell::getDirection() const
{
	return direction;
}

void Cell::setColor( const Color col)
{
	color = col;
}

const Color Cell::getColor() const
{
	return color;
}
